﻿using System.Linq.Expressions;
using Bing.Data.Sql.Builders.Core;
using Bing.Data.Sql.Builders.Internal;
using Bing.Extensions;
using Bing.Properties;

namespace Bing.Data.Sql.Builders.Clauses;

/// <summary>
/// Order By子句
/// </summary>
public class OrderByClause : IOrderByClause
{
    /// <summary>
    /// 排序项列表
    /// </summary>
    private readonly List<OrderByItem> _items;

    /// <summary>
    /// Sql方言
    /// </summary>
    private readonly IDialect _dialect;

    /// <summary>
    /// 实体解析器
    /// </summary>
    private readonly IEntityResolver _resolver;

    /// <summary>
    /// 实体别名注册器
    /// </summary>
    private readonly IEntityAliasRegister _register;

    /// <summary>
    /// 初始化一个<see cref="OrderByClause"/>类型的实例
    /// </summary>
    /// <param name="dialect">Sql方言</param>
    /// <param name="resolver">实体解析器</param>
    /// <param name="register">实体别名注册器</param>
    /// <param name="items">排序项列表</param>
    public OrderByClause(IDialect dialect, IEntityResolver resolver, IEntityAliasRegister register,
        List<OrderByItem> items = null)
    {
        _items = items ?? new List<OrderByItem>();
        _dialect = dialect;
        _resolver = resolver;
        _register = register;
    }

    /// <summary>
    /// 克隆
    /// </summary>
    /// <param name="register">实体别名注册器</param>
    public virtual IOrderByClause Clone(IEntityAliasRegister register) => new OrderByClause(_dialect, _resolver, register, new List<OrderByItem>(_items));

    /// <summary>
    /// 排序
    /// </summary>
    /// <param name="order">排序列表</param>
    /// <param name="tableAlias">表别名</param>
    public void OrderBy(string order, string tableAlias = null)
    {
        if (string.IsNullOrWhiteSpace(order))
            return;
        order.Split(',').ToList().ForEach(column => AddItem(column, tableAlias: tableAlias));
    }

    /// <summary>
    /// 添加排序项
    /// </summary>
    /// <param name="column">排序列</param>
    /// <param name="desc">是否倒序</param>
    /// <param name="type">实体类型</param>
    /// <param name="tableAlias">表别名</param>
    protected void AddItem(string column, bool desc = false, Type type = null, string tableAlias = null)
    {
        if (column.IsEmpty())
            return;
        if (Exists(column, tableAlias))
            return;
        _items.Add(new OrderByItem(column, desc, type, prefix: tableAlias));
    }

    /// <summary>
    /// 是否已存在
    /// </summary>
    /// <param name="column">排序列</param>
    /// <param name="tableAlias">表别名</param>
    protected bool Exists(string column, string tableAlias)
    {
        var item = new OrderByItem(column, prefix: tableAlias);
        return _items.Exists(t =>
            t.Column.ToLower() == item.Column.ToLower() &&
            (item.Prefix.IsEmpty() || t.Prefix?.ToLower() == item.Prefix?.ToLower()));
    }

    /// <summary>
    /// 排序
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <param name="column">排序列</param>
    /// <param name="desc">是否倒序</param>
    public void OrderBy<TEntity>(Expression<Func<TEntity, object>> column, bool desc = false)
    {
        if (column == null)
            return;
        AddItem(_resolver.GetColumn(column), desc, typeof(TEntity));
    }

    /// <summary>
    /// 添加到OrderBy子句
    /// </summary>
    /// <param name="sql">Sql语句</param>
    public void AppendSql(string sql)
    {
        if (string.IsNullOrWhiteSpace(sql))
            return;
        sql = Helper.ResolveSql(sql, _dialect);
        _items.Add(new OrderByItem(sql, raw: true));
    }

    /// <summary>
    /// 验证
    /// </summary>
    /// <param name="isPage">是否分页</param>
    public void Validate(bool isPage)
    {
        if (isPage == false)
            return;
        if (_items.Count == 0)
            throw new ArgumentException(LibraryResource.OrderIsEmptyForPage);
    }

    /// <summary>
    /// 获取Sql
    /// </summary>
    public string ToSql()
    {
        if (_items.Count == 0)
            return null;
        return $"Order By {_items.Select(t => t.ToSql(_dialect, _register)).Join()}";
    }
}